"""
认证相关API路由
"""
from datetime import timedelta
from fastapi import APIRouter, Depends, HTTPException, status, Request
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from sqlalchemy.orm import Session
from typing import Optional

from core.database import get_db
from core.auth import verify_password, get_password_hash, create_access_token, verify_token, check_login_attempts, record_login_attempt, validate_password
from models.database import User
from models.schemas import UserCreate, UserLogin, Token, UserResponse, BaseResponse
from core.config import get_settings
from core.logger import api_logger, log_api_call

router = APIRouter()
security = HTTPBearer()
settings = get_settings()


def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(security),
    db: Session = Depends(get_db),
    request: Request = None
) -> User:
    """获取当前用户"""
    token = credentials.credentials
    payload = verify_token(token)
    
    if payload is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token"
        )
    
    user_id = payload.get("sub")
    if user_id is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token"
        )
    
    user = db.query(User).filter(User.id == user_id).first()
    if user is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="User not found"
        )
    
    if not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="User is inactive"
        )
    
    # 更新最后登录时间
    from datetime import datetime
    user.last_login = datetime.now()
    db.commit()
    
    # 将用户ID设置到request.state中，供日志装饰器使用
    if request:
        request.state.user_id = str(user_id)
    
    return user


def get_current_admin(
    current_user: User = Depends(get_current_user),
    request: Request = None
) -> User:
    """获取当前管理员用户"""
    if current_user.role != "admin":
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Admin access required"
        )
    
    # 将用户ID设置到request.state中，供日志装饰器使用
    if request:
        request.state.user_id = str(current_user.id)
    
    return current_user


def get_current_user_optional(
    credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
    db: Session = Depends(get_db),
    request: Request = None
) -> Optional[User]:
    """获取当前用户（可选认证）"""
    if credentials is None:
        return None
    
    try:
        token = credentials.credentials
        payload = verify_token(token)
        
        if payload is None:
            return None
        
        user_id = payload.get("sub")
        if user_id is None:
            return None
        
        user = db.query(User).filter(User.id == user_id).first()
        if user is None:
            return None
        
        if not user.is_active:
            return None
        
        # 将用户ID设置到request.state中，供日志装饰器使用
        if request:
            request.state.user_id = str(user_id)
        
        return user
    except Exception:
        # 如果认证过程中出现任何异常，返回None而不是抛出异常
        return None


@router.post("/login", response_model=Token)
@log_api_call
async def login(user_credentials: UserLogin, request: Request, db: Session = Depends(get_db)):
    """用户登录"""
    # 获取客户端IP
    client_ip = request.client.host if request.client else None
    
    # 检查登录尝试次数
    if not check_login_attempts(user_credentials.username, client_ip):
        api_logger.log_task_event("auth", "login_blocked", {"username": user_credentials.username, "ip": client_ip})
        raise HTTPException(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            detail="登录尝试次数过多，请30分钟后再试"
        )
    
    user = db.query(User).filter(User.username == user_credentials.username).first()
    
    if not user or not verify_password(user_credentials.password, user.password_hash, user_credentials.client_hash):
        # 记录登录失败
        record_login_attempt(user_credentials.username, client_ip)
        api_logger.log_task_event("auth", "login_failed", {"username": user_credentials.username, "ip": client_ip})
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid username or password"
        )
    
    if not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="User account is inactive"
        )
    
    # 创建访问令牌
    access_token_expires = timedelta(seconds=settings.jwt_expire_seconds)
    access_token = create_access_token(
        data={"sub": str(user.id), "username": user.username},
        expires_delta=access_token_expires
    )
    
    api_logger.log_task_event("auth", "login_success", {"user_id": user.id, "username": user.username})
    
    return Token(
        access_token=access_token,
        token_type="bearer",
        expires_in=settings.jwt_expire_seconds,
        user=UserResponse.from_orm(user)
    )


@router.post("/register", response_model=UserResponse)
@log_api_call
async def register(user_data: UserCreate, db: Session = Depends(get_db)):
    """用户注册"""
    # 检查用户名是否已存在
    if db.query(User).filter(User.username == user_data.username).first():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Username already registered"
        )
    
    # 检查邮箱是否已存在
    if db.query(User).filter(User.email == user_data.email).first():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Email already registered"
        )
    
    # 验证密码强度
    is_valid, errors = validate_password(user_data.password)
    if not is_valid:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Password too weak: " + ", ".join(errors)
        )
    
    # 创建新用户
    hashed_password = get_password_hash(user_data.password)
    db_user = User(
        username=user_data.username,
        email=user_data.email,
        password_hash=hashed_password,
        role=user_data.role
    )
    
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    
    api_logger.log_task_event("auth", "register_success", {"user_id": db_user.id, "username": db_user.username})
    
    return UserResponse.from_orm(db_user)


@router.get("/me", response_model=UserResponse)
@log_api_call
async def get_current_user_info(current_user: User = Depends(get_current_user)):
    """获取当前用户信息"""
    return UserResponse.from_orm(current_user)


@router.post("/logout", response_model=BaseResponse)
@log_api_call
async def logout(current_user: User = Depends(get_current_user)):
    """用户登出"""
    api_logger.log_task_event("auth", "logout", {"user_id": current_user.id, "username": current_user.username})
    
    return BaseResponse(
        success=True,
        message="Logout successful"
    )


@router.post("/refresh", response_model=Token)
@log_api_call
async def refresh_token(current_user: User = Depends(get_current_user)):
    """刷新访问令牌"""
    access_token_expires = timedelta(seconds=settings.jwt_expire_seconds)
    access_token = create_access_token(
        data={"sub": str(current_user.id), "username": current_user.username},
        expires_delta=access_token_expires
    )
    
    return Token(
        access_token=access_token,
        token_type="bearer",
        expires_in=settings.jwt_expire_seconds,
        user=UserResponse.from_orm(current_user)
    )


@router.get("/validate", response_model=BaseResponse)
@log_api_call
async def validate_token(current_user: User = Depends(get_current_user)):
    """验证令牌有效性"""
    return BaseResponse(
        success=True,
        message="Token is valid",
        data={"user_id": current_user.id, "username": current_user.username}
    )


# 导出路由器
auth_router = router